package au.edu.qut.bpm.genbinder.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import org.deckfour.xes.model.XLog;
import org.deckfour.xes.out.XSerializer;
import org.deckfour.xes.out.XesXmlSerializer;
import org.uncommons.watchmaker.framework.EvolutionObserver;
import org.uncommons.watchmaker.framework.PopulationData;
import org.uncommons.watchmaker.swing.AbortControl;

import au.edu.qut.bpm.genbinder.GeneticBinder;
import au.edu.qut.bpm.genbinder.genetic.genesis.LogGreedyFactory;
import au.edu.qut.bpm.genbinder.genetic.genesis.LogRandomizedFactory;
import au.edu.qut.bpm.genbinder.genetic.other.LogRepairer;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.util.LogToXESConverter;

public class MainPanel extends JPanel implements EvolutionObserver<ConcreteEventLog> {
	private static final long serialVersionUID = -6299001227159297555L;
	
	private static CaseListPanel listPanel;
	private JLabel infoLabel;
	public static ConcreteEventLog log;

	public static ConcreteEventLog newLog;


	private JButton newButton, greedyButton, solveButton, bruteButton, repairButton, saveButton;
	private AbortControl abortControl;
	
	public MainPanel() {
		this.setLayout(new BorderLayout());
		this.setSize(new Dimension(400, 400));
		
		newLog = null;
		
		infoLabel = new JLabel("GenBinder Prototype");
		listPanel = new CaseListPanel();
	
		this.add(this.createButtonPanel(), BorderLayout.SOUTH);
		this.add(infoLabel, BorderLayout.NORTH);
		
		JScrollPane scrollPane = new JScrollPane(listPanel);
		this.add(scrollPane, BorderLayout.CENTER);
		//scrollPane.setVisible(false);
		///*
		try {
			if (newLog == null) {
				//abortControl = new AbortControl();
				//abortControl.reset();
				GeneticBinder.createTask(GeneticBinder.bestCandidateLog, this,	abortControl).execute();
				
			} else {
				//GeneticBinder.createTask(newLog, this,	abortControl).execute();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//*/
	}
	
	private JComponent createButtonPanel() {
		final MainPanel self = this;
		
		JPanel buttonPanel = new JPanel(new FlowLayout());
		
		newButton = new JButton("New");
		newButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				LogRandomizedFactory f = new LogRandomizedFactory(log);
				//LogSequentialScheduleFactory f = new LogSequentialScheduleFactory(log.getAbstractLog());
				ConcreteEventLog log = f.generateRandomCandidate(new Random());
				System.err.println("Log is safe: "+log.isLogSafe());
				System.err.println("Log is valid: "+log.isLogValid());
				showLog(log);
			}
		});
		
		greedyButton = new JButton("Greedy");
		greedyButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				LogGreedyFactory f = new LogGreedyFactory(log);
				ConcreteEventLog log = f.generateRandomCandidate(new Random());
				
				//LogSequentialScheduleFactory f = new LogSequentialScheduleFactory(log.getAbstractLog());
				//log = f.generateRandomCandidate(new Random());
				
				System.err.println("Log is safe: "+log.isLogSafe());
				System.err.println("Log is valid: "+log.isLogValid());
				showLog(log);
			}
		});
		
		abortControl = new AbortControl();
		solveButton = new JButton("Solve (Genetic Algorithm)");
		solveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				Date date = new Date();
				System.err.println("Start: " + date.toString());
				abortControl.reset();
				try {
					if (newLog == null) {
						GeneticBinder.createTask(log, self,	abortControl).execute();
					} else {
						GeneticBinder.createTask(newLog, self,	abortControl).execute();
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		});
		
		abortControl = new AbortControl();
		bruteButton = new JButton("Solve (Brute Force)");
		bruteButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				abortControl.reset();
				try {
					if (newLog == null) {
						GeneticBinder.createTask(log, self,	abortControl).execute();
					} else {
						
							GeneticBinder.createTask(newLog, self, abortControl).execute();
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				
			}
		});
		
		repairButton = new JButton("Repair");
		repairButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				//CopyOfLogRepairer repairer = new CopyOfLogRepairer();
				LogRepairer repairer = new LogRepairer();
				List<ConcreteEventLog> l = new ArrayList<ConcreteEventLog>();
				l.add(log);
				l = repairer.apply(l, new Random());
				showLog(l.get(0));
				
				//log.RepairOneLog();
				showLog(log);
				//log = l.get(0);
				newLog = l.get(0);
				//newLog = log;
				System.err.println("Log is safe: "+ newLog.isLogSafe());
				System.err.println("Log is valid: "+ newLog.isLogValid());
				//showLog(log);
			}
		});
		
		saveButton = new JButton("Save as XES");
		saveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser fc = new JFileChooser();
				int returnVal = fc.showSaveDialog(self);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					File file = fc.getSelectedFile();
					XLog xesLog = LogToXESConverter.createLog(log, CaseListPanel.ZEROBLOCK, GeneticBinder.BLOCK_DURATION);
					XSerializer serializer = new XesXmlSerializer();
					try {
						serializer.serialize(xesLog, new FileOutputStream(file));
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}
			}
		});

		buttonPanel.add(newButton);
		buttonPanel.add(greedyButton);
		buttonPanel.add(solveButton);
		buttonPanel.add(bruteButton);
		buttonPanel.add(abortControl.getControl());
		abortControl.getControl().setEnabled(false);
		buttonPanel.add(repairButton);
		buttonPanel.add(saveButton);
		
		return buttonPanel;
	}
	
	public void showInfo(String text) {
		infoLabel.setText(text);
	}
	
	public static void showLog(ConcreteEventLog log) {
		MainPanel.log = log;
		MainPanel.listPanel.showLog(log);
	}

	@Override
	public void populationUpdate(PopulationData<? extends ConcreteEventLog> p) {
		GeneticBinder.bestCandidateLog = p.getBestCandidate();
		MainPanel.log = GeneticBinder.bestCandidateLog;
		//showLog(p.getBestCandidate());
		//showInfo(p.getGenerationNumber() + " | mean fitness: " + p.getMeanFitness() + " | best fitness: " + p.getBestCandidateFitness() +
		//		" | safe: " + log.isLogSafe() + " | valid: " + log.isLogValid());
	}
	
	

}
